/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package xenon3d.scene;

import java.nio.FloatBuffer;
import javax.media.opengl.GL2;

/**
 * The GeometryArray object contains an interleaved array of coordinates, colors,
 * normals and texture coordinates that describe point, line, triangle, quad or
 * polygon geometry. All colors values used in the vertex data must be in the
 * range [0.0,1.0]. Values outside this range will cause undefined results. All
 * normals used in the vertex data must be unit length vectors. That is their
 * geometric length must be 1.0. Normals that are not unit length vectors will
 * cause undefined results.
 *
 * @author Volker Everts
 * @version 0.1 - 18.08.2008: Created
 * @version 0.2 - 04.09.2011: Adapted
 */
public class GeometryArray extends Geometry {
    
    // <editor-fold defaultstate="collapsed" desc=" Private Fields ">

    /** The vertex format of the vertex data. */
    private VertexFormat vertexFormat;

    /** The primitive type used in drawing this geometry object. */
    private PrimType primType;

    /** The number of vertices that make up vertex data. */
    private int vertexCount;

    /** The buffer that holds the vertex data. */
    private FloatBuffer vertices;

    /** The texture coords vertical flip flag. */
    private boolean flipped;

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc=" Initialization ">

    /**
     * Creates a new GeometryArray based on the suplied vertex data. The vertex
     * data will be interpreted as having the vertex format VertexNormalTex and
     * the primitive type TriangleStrip. The number of vertices is calculated
     * from the length of the supplied vertex array divided by the vertex size
     * for the format VertexNormalTex, which is 8. If there is a remainder from
     * this division operation, the additinal vertices in the array are ignored.
     * @param vertexData a float array containing the interleaved vertex data
     */
    public GeometryArray(float[] vertexData) {
        this(VertexFormat.VertexNormalTex, PrimType.TriangleStrip, vertexData);
    }

    /**
     * Creates a new GeometryArray based on the suplied prim type and vertex
     * data. The vertex data will be interpreted as having the vertex format
     * VertexNormalTex. The number of vertices is calculated from the length of
     * the supplied vertex array divided by the vertex size for the format
     * VertexNormalTex, which is 8. If there is a remainder from this division
     * operation, the additinal vertices in the array are ignored.
     * @param primType the prim type
     * @param vertexData a float array containing the interleaved vertex data
     */
    public GeometryArray(PrimType primType, float[] vertexData) {
        this(VertexFormat.VertexNormalTex, primType, vertexData);
    }

    /**
     * Creates a new GeometryArray based on the suplied vertex format, prim type
     * and vertex data. The number of vertices is calculated from the length of
     * the supplied vertex array divided by the vertex size for the format
     * VertexNormalTex, which is 8. If there is a remainder from this division
     * operation, the additinal vertices in the array are ignored.
     * @param format the vertex format
     * @param prim the prim type
     * @param vertexData a float array containing the interleaved vertex data
     */
    public GeometryArray(VertexFormat format, PrimType prim, float[] vertexData) {
        vertexFormat = format;
        primType = prim;
        vertexCount = vertexData.length / format.size();
        int count = vertexCount * format.size();
        assert count == vertexData.length : "Count=" + count + " : length=" + vertexData.length + " (" + toString() + ")";
        vertices = FloatBuffer.allocate(count);
        vertices.put(vertexData, 0, count);
        vertices.flip();
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc=" Public Properties ">

    /**
     * Returns the vertex format.
     * @return the vertex format
     */
    public final VertexFormat getVertexFormat() {
        return vertexFormat;
    }

    /**
     * Returns the primitive type used to render this geometry array.
     * @return the primitive type
     */
    public final PrimType getPrimitiveType() {
        return primType;
    }

    /**
     * Returns the size of the vertex data in floating point units. This is the
     * amount of float values that make up the vertex data as opposed to the
     * vertex size which gives the number of vertices. One vertex consists of
     * 3 to 12 float values, depending on the vertex format. The returned size
     * is the vertex size of one vertex times the vertex count.
     * return the size of the geometry arry
     * @return the total size of the geometry float buffer in float units
     */
    public final int getSize() {
        return vertices.capacity();
    }

    /**
     * Returns the number of vertices that make up the vertex data.
     * @return the number of vertices
     */
    public final int getVertexCount() {
        return vertexCount;
    }

    /**
     * Returns whether texture coordinates are vertically flipped.
     * @return true, if texture coordinates are flipped
     */
    public final boolean areTextureCoordsVerticallyFlipped() {
        return flipped;
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc=" Public Methods ">

    /**
     * Performs vertical flipping of all texture coordinates.
     */
    public void flipTextureCoordsVertically() {
        if (vertexFormat.hasTexture()) {
            int n = 1;
            for (int i = 0; i < vertexCount; i++) {
                vertices.put(n, 1.0f - vertices.get(n));
                n += vertexFormat.size();
            }
            flipped = !flipped;
        }
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc=" Package Private Methods (OpenGL)  ">

    @Override
    void draw(GL2 gl) {
        gl.glInterleavedArrays(vertexFormat.value(), 0, vertices);
        gl.glDrawArrays(primType.value(), 0, vertexCount);
    }

    // </editor-fold>

} // end class GeometryArray